package com.starlinkdt.proxy.interceptor;

import com.github.lianjiatech.retrofit.spring.boot.interceptor.BasePathMatchInterceptor;
import com.starlinkdt.common.context.RequestIdContextHolder;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 请求日志记录处理
 *
 * @author system
 */
@Component
public class RetrofitInterceptor extends BasePathMatchInterceptor
{
    private static final Logger log = LoggerFactory.getLogger(RetrofitInterceptor.class);

    @Override
    protected Response doIntercept(Chain chain) throws IOException {
        return null;
    }

    public Response logChainProceed(Chain chain, Request request) throws IOException {

        // 设置日志记录格式
        String logFormat = "RetrofitInterceptor："
                + "[REQUEST_ID : {}] [COST_TIME : {}ms] [URL : {}] [HTTP_METHOD : {}] "
                + "[HEADER : {}] [QUERY : {}] [BODY : {}] [RESPONSE : {}]";

        List<String> logArg = new ArrayList<>();
        String responseResult = "";

        long startTime = System.currentTimeMillis();
        try {
            Response response = chain.proceed(request);
            // 获取 RESPONSE
            responseResult = getResponseInfo(response);
            return response;
        } catch (Exception e) {
            // 获取 RESPONSE
            responseResult = e.getMessage();
            throw e;
        } finally {
            // 请求ID
            logArg.add(RequestIdContextHolder.getContext());
            // 获取 COST_TIME
            long endTime = System.currentTimeMillis();
            logArg.add(String.valueOf(endTime - startTime));
            // 获取 URL
            logArg.add(request.url().toString());
            // 获取 METHOD
            logArg.add(request.method());
            // 获取 HEADER
            logArg.add(request.headers().toMultimap().toString());
            // 获取 QUERY
            logArg.add(getQueryInfo(request));
            // 获取 BODY
            logArg.add(getRequestInfo(request));
            // 获取 RESPONSE
            logArg.add(responseResult);

            // 记录日志
            log.info(logFormat, logArg.toArray());
        }
    }

    private String getQueryInfo(Request request) {
        String str = "";
        if (request == null) {
            return str;
        }
        Set<String> queryParameterNames = request.url().queryParameterNames();
        if (queryParameterNames.isEmpty()) {
            return str;
        }
        Map<String, String> queryMap = new HashMap<>();
        queryParameterNames.forEach(v -> {
            queryMap.put(v, request.url().queryParameter(v));
        });
        str = queryMap.toString();

        return str;
    }

    private String getRequestInfo(Request request) {
        String str = "";
        if (request == null) {
            return str;
        }
        RequestBody requestBody = request.body();
        if (requestBody == null) {
            return str;
        }
        try {
            Buffer bufferedSink = new Buffer();
            requestBody.writeTo(bufferedSink);
            str = bufferedSink.readString(StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }

    private String getResponseInfo(Response response) {
        String str = "";
        if (response == null || !response.isSuccessful()) {
            return str;
        }
        ResponseBody responseBody = response.body();
        assert responseBody != null;
        long contentLength = responseBody.contentLength();
        BufferedSource source = responseBody.source();
        try {
            source.request(Long.MAX_VALUE); // Buffer the entire body.
        } catch (IOException e) {
            e.printStackTrace();
        }
        Buffer buffer = source.buffer();
        if (contentLength != 0) {
            str = buffer.clone().readString(StandardCharsets.UTF_8);
        }
        return str.replace("\n", "").replace(" ", "");
    }

}
